package com.vonchange.headb.utils.xml;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.XPP3Reader;
import org.xmlpull.v1.XmlPullParserException;

import com.vonchange.headb.core.bean.Join;
import com.vonchange.headb.core.exception.MyRuntimeException;
import com.vonchange.headb.utils.HBase;
import com.vonchange.headb.utils.md5.HMD5Util;
import com.vonchange.headb.utils.string.HStringUtils;
import com.vonchange.headb.utils.xml.bean.XmlCache;

/**
 * xml组件
 * @author von_change@163.com
 * @date 2015-6-14 下午6:30:58
 */
public class HXmlUtils extends HBase {
	private static String VIEW = "view";
	private static String ORM = "orm";
	private static String SQL = "sql";
	private static String CUDSQL = "cudSql";
	private static String COLUMN = "column";
	private static String ID = "id";
	private static String JOIN="join";
	private static String ALIAS="alias";
	private static String FIELD="field";
	private static String CLASS="class";
	private Document document;
	private XmlCache xmlCache;
	//private  Cache<String,XmlCache> xmlFileCacheMap = new LRUCache<String,XmlCache>(1024*1024);
	private static Map<String, XmlCache> xmlFileCacheMap = new HashMap<String, XmlCache>();
	public HXmlUtils(File xml) {
		long lastModifiedTime = xml.lastModified();
		//logger.debug(HLogUtils.format("xml位置",  xml.getPath()));
		if (lastModifiedTime != 0) {
		String md5File = HMD5Util.getMD5(xml.getPath()+lastModifiedTime);
		if (null != xmlFileCacheMap.get(md5File)) {
			    this.xmlCache=xmlFileCacheMap.get(md5File);
				this.document = xmlCache.getDoc();
	    } else {
	         	this.document = load(xml);	
	    	    this.xmlCache= new XmlCache().setDoc(document);    
			    xmlFileCacheMap.put(md5File, this.xmlCache);
			}
		} else {
			throw new MyRuntimeException(xml.getPath()+"文件找不到!");
		}
	}

	public Document load(File xml) {
		//SAXReader reader = new SAXReader();
		XPP3Reader reader = new XPP3Reader();  	  
		Document document = null;
		try {
			document = reader.read(xml);
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return document;
	}
	
	/**
	 * 根据Id获得Label的值
	 * @param label
	 * @param id
	 * @return Label的值
	 */
	@SuppressWarnings("unchecked")
	public  String getLabel(String label, String id) {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path=label+"/"+id;
		if(null!=valueCacheMap.get(path)){
			return valueCacheMap.get(path).toString();
		}
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element(label + "s");
		if (null == hqlsElement) {
			return null;
		}
		List<Element> hqlElements = hqlsElement.elements(label);
		for (Element element : hqlElements) {
			Attribute attribute = element.attribute(ID);
			if (null == attribute) {
				if (null == id) {
					valueCacheMap.put(path, element.getTextTrim());
					return element.getTextTrim();
				}
			}
			if (null != attribute) {
				if (attribute.getValue().equals(id)) {	
					valueCacheMap.put(path, element.getTextTrim());
					return element.getTextTrim();
				}
			}
		}
		return null;
	}
	/**
	 * 获得更新的SQL
	 * @param id
	 * @return 更新的SQL
	 */
	public String getUpdateSql(String id) {
		return getLabel(CUDSQL, id);
	}
	/**
	 * 获得heaView的SQL
	 * @return heaView里的SQL
	 */
	public String getView() {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path="view";
		if(null!=valueCacheMap.get(path)){

			return (String) valueCacheMap.get(path);
		}
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element(VIEW );
		if (null == hqlsElement) {
			return null;
		}
		 valueCacheMap.put(path, hqlsElement.getTextTrim());
	     return hqlsElement.getTextTrim();
	}
	/**
	 * 获得Sql片段
	 * @param id
	 * @return Sql片段
	 */
	public String getSql(String id) {
		return getLabel(SQL, id);
	}
	/**
	 * 获得字段
	 * @param id
	 * @return 字段SQL
	 */
	public String getColumn(String id) {
		return getLabel(COLUMN, id);
	}
	/**
	 *根据alias获得连接信息
	 * @param alias
	 * @return 连接信息
	 */
	@SuppressWarnings("unchecked")
	public Join getJoin(String alias) {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path=JOIN+"/alias/"+ALIAS;
		if(null!=valueCacheMap.get(path)){
			return (Join) valueCacheMap.get(path);
		}
		Join join = new Join();
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element(JOIN + "s");
		if (null == hqlsElement) {
			return null;
		}
		List<Element> hqlElements = hqlsElement.elements(JOIN);
		for (Element element : hqlElements) {
			Attribute attribute = element.attribute(ALIAS);
			if (null == attribute) {
				 throw new RuntimeException("必须有别名！");
			}
			if (null != attribute) {
				if (attribute.getValue().equals(alias)) {
					join.setAlias(alias);
					String fieldName=element.attributeValue(FIELD).trim();
					join.setField(fieldName);
					String classPath=element.attributeValue(CLASS).trim();
					join.setClasspath(classPath);
					String[] fields=fieldName.split("\\.");
					join.setLevel(fields.length);
					if(fields.length>1){
						join.setDependField(HStringUtils.substringBeforeLast(fieldName, "."));
					}
					join.setJoinSql(element.getTextTrim());
					valueCacheMap.put(path, join);
					return join;
				}
			}
		}
		return null;
	}
	/**
	 * 根据field找到alias
	 * @param filed
	 * @return alias
	 */
	@SuppressWarnings("unchecked")
	public String getDependAliasByField(String filed) {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path=JOIN+"/field/"+FIELD;
		if(null!=valueCacheMap.get(path)){
			return  (String) valueCacheMap.get(path);
		}
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element(JOIN + "s");
		if (null == hqlsElement) {
			return null;
		}
		List<Element> hqlElements = hqlsElement.elements(JOIN);
		for (Element element : hqlElements) {
			Attribute attribute = element.attribute(FIELD);
			if (null == attribute) {
				 throw new RuntimeException("必须有字段对应！");
			}
			if (null != attribute) {
				if (attribute.getValue().equals(filed)) {
					valueCacheMap.put(path, element.attributeValue(ALIAS).trim());
					return element.attributeValue(ALIAS).trim();
				}
			}
		}
		return null;
	}
	public String getOrmType() {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path="config/orm";
		if(null!=valueCacheMap.get(path)){
			return (String) valueCacheMap.get(path);
		}
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element(ORM );
		if (null == hqlsElement) {
			return null;
		}
		 valueCacheMap.put(path, hqlsElement.getTextTrim());
	     return hqlsElement.getTextTrim();
	}
	public boolean sqlIsOrm() {
		String ormType=this.getOrmType();
		if("false".equals(ormType)){
			return false;
		}
		if("true".equals(ormType)){
			return true;
		}
		return true;
	}
	/**
	 * 获得可以转换的时间格式
	 * @return 可以转换的时间格式
	 */
	@SuppressWarnings("unchecked")
	public String[] getPattern() {
		Map<String,Object> valueCacheMap=this.xmlCache.getValueMap();
		String path="config/pattern/";
		if(null!=valueCacheMap.get(path)){
			return (String[]) valueCacheMap.get(path);
		}
		List<String> patterns = new ArrayList<String>();
		Element rootElement = document.getRootElement();
		Element hqlsElement = rootElement.element("pattern");
		if (null == hqlsElement) {
			valueCacheMap.put(path, patterns.toArray(new String[0]));
			return patterns.toArray(new String[0]);
		}
		List<Element> hqlElements = hqlsElement.elements("format");
		for (Element element : hqlElements) {
			if (HStringUtils.isNotBlank(element.getTextTrim())) {
				patterns.add(element.getTextTrim());
			}
		}
		valueCacheMap.put(path, patterns.toArray(new String[patterns.size()]));
		return patterns.toArray(new String[patterns.size()]);
	}

}
